# encoding: utf-8

from util.log import getLogger
logger = getLogger(10)

PACK_HEAD_HEART = bytes([0xa0, 0x3f, 0x3f, 0xa0])
PACK_HEAD_ERROR = bytes([0xa0, 0x3e, 0x3e, 0xa0])

PACK_HEAD_CMD  = bytes([0xa1, 0x3f, 0x3f, 0xa1])
PACK_HEAD_DATA = bytes([0xa2, 0x3f, 0x3f, 0xa2])

import json

def dict2json(msg: dict):
    """ return a bytes-like data """
    json_msg = json.dumps(msg)
    bytes_msg = json_msg.encode()
    return bytes_msg

def json2dict(msg: bytes):
    """ return a dict-like data """
    str_msg = msg.decode()
    dict_msg = json.loads(str_msg)
    return dict_msg

class DpmDataTrans:
    def __init__(self):
        self.dict_registers = {}  # "license": (ip, port)
        self.map_connection = {}  # (ip, port): (ip2, port2)

    def set_func_send(self, callback):
        self.send_msg = callback

    def send_cmd(self, bytes_data, addr=None):
        pack = PACK_HEAD_CMD + bytes_data
        self.send_msg(pack, addr)

    def send_data(self, bytes_data, addr=None):
        pack = PACK_HEAD_DATA + bytes_data
        self.send_msg(pack, addr)

    def parse_reply(self, msg: bytes, addr=None):
        # logger.debug("接收到回复：【{}】".format(msg))

        msg_head = msg[:4]
        msg_body = msg[4:]

        if msg_head == PACK_HEAD_CMD:
            dict_msg = json2dict(msg_body)
            if dict_msg["type"] == "Register Assist":
                print("注册回复：", dict_msg["msg"])
            elif dict_msg["type"] == "Register List":
                print("协助申请列表：", dict_msg["msg"])
            elif dict_msg["type"] == "Connect to Remote":
                if dict_msg["msg"] == "true":
                    print("协助连接成功")
                    self.on_connected(addr)
                else:
                    print("协助连接失败：【{}】".format(dict_msg['msg']))
            elif dict_msg["type"] == "Connection Shutdown":
                print("远程对象已断开连接")
            elif dict_msg["type"] == "Request Accept":
                print("已获取到远程协助")
                self.on_assisted(addr)
            else:
                print("未解析命令【{}】".format(msg))

        elif msg_head == PACK_HEAD_DATA:
            # logger.debug("接收到数据【{}】".format(msg_body))
            self.on_accept_data(msg_body, addr)

        else:
            logger.error("Fail to parse the message【{}】.".format(msg))

    def reply(self, msg: bytes, addr=None):
        # logger.debug("接收到消息：【{}】".format(msg))

        msg_head = msg[:4]
        msg_body = msg[4:]

        if msg_head == PACK_HEAD_CMD:
            dict_msg = json2dict(msg_body)
            if dict_msg["type"] == "Register Assist":
                self.on_register_assist(dict_msg, addr)
            elif dict_msg["type"] == "Register List":
                self.on_register_list(dict_msg, addr)
            elif dict_msg["type"] == "Connect to Remote":
                self.on_connect_remote(dict_msg, addr)
            elif dict_msg["type"] == "Connection Shutdown":
                self.on_connect_close(addr)
            else:
                err = "Unkown command [{}]".format(msg)
                err_msg = PACK_HEAD_ERROR + err.encode()
                self.send_msg(err_msg, addr)

        elif msg_head == PACK_HEAD_DATA:
            # logger.debug("转发数据【{}】".format(msg))
            self.on_forward_data(msg, addr)

        else:
            err = "Unkown request [{}]".format(msg)
            err_msg = PACK_HEAD_ERROR + err.encode()
            self.send_msg(err_msg, addr)

    def register_assist(self, license):
        bytes_data = dict2json({
            "type": "Register Assist",
            "msg": license
        })
        self.send_cmd(bytes_data)

    def on_register_assist(self, dict_msg, addr):
        license_num = dict_msg["msg"]
        if license_num in self.dict_registers:
            already = self.dict_registers[license_num]
            dict_msg["msg"] = "当前序列号已申请远程协助【{}】".format(already)
            self.send_cmd(dict2json(dict_msg), addr)
            return

        self.dict_registers[license_num] = addr
        dict_msg["msg"] = "true"
        self.send_cmd(dict2json(dict_msg), addr)

    def register_list(self):
        bytes_data = dict2json({"type": "Register List"})
        self.send_cmd(bytes_data)

    def on_register_list(self, dict_msg, addr):
        dict_ = {}  # license: "222.182.100.1:31610"
        for key, value in self.dict_registers.items():
            dict_[key] = "{}:{}".format(*value)
        dict_msg["msg"] = dict_
        self.send_cmd(dict2json(dict_msg), addr)

    def connect_to_remote(self, ip_addr=None):
        if ip_addr is None:
            ip_addr = input("输入连接的远程地址: ")  # "222.182.100.1:31610"
        bytes_data = dict2json({"type": "Connect to Remote", "msg": ip_addr})
        self.send_cmd(bytes_data)

    def on_connect_remote(self, dict_msg, addr):
        if addr in self.map_connection:
            dict_msg["msg"] = "你正在协助远程客户端【{}】".format(addr)
            self.send_cmd(dict2json(dict_msg), addr)
            return

        host, port = dict_msg["msg"].split(":")
        port = int(port)
        ip_conn = (host, port)

        if ip_conn not in list(self.dict_registers.values()):
            dict_msg["msg"] = "未知的协助对象【{}】".format(ip_conn)
            self.send_cmd(dict2json(dict_msg), addr)
            return

        if ip_conn in self.map_connection:
            dict_msg["msg"] = "协助对象已连接到其他客户端【{}】".format(ip_conn)
            self.send_cmd(dict2json(dict_msg), addr)
            return

        self.map_connection[addr] = ip_conn
        # 对调，但对于映射重写，不能删除原对调pair
        self.map_connection[ip_conn] = addr
        logger.debug(self.map_connection)

        dict_msg["msg"] = "true"
        self.send_cmd(dict2json(dict_msg), addr)
        self.send_cmd(dict2json({"type": "Request Accept"}), ip_conn)

    def on_connect_close(self, addr):
        """ 如果重写，请继承父类 super().on_connect_close(addr) """
        for key, value in self.dict_registers.items():
            if value == addr:
                del self.dict_registers[key]
                break

        if addr in self.map_connection:
            conn = self.map_connection[addr]
            self.send_cmd(dict2json({"type": "Connection Shutdown"}), conn)
            del self.map_connection[addr]
            del self.map_connection[conn]

    def on_forward_data(self, msg, addr):
        if addr not in self.map_connection:
            err = "未能连接到远程计算机"
            err_msg = PACK_HEAD_ERROR + err.encode()
            self.send_msg(err_msg, addr)
        else:
            target = self.map_connection[addr]
            self.send_msg(msg, target)

    def on_connected(self, addr):
        # 连接到远程计算机
        pass

    def stop(self):
        pass

    def on_assisted(self, addr):
        # 协助连接成功后，发送测试数据
        self.send_data(b"ABC", addr)

    def on_accept_data(self, data, addr):
        # 接收到数据
        print("Recv Msg【{}】".format(data))
